home *** CD-ROM | disk | FTP | other *** search
- /* MiniMailer.c */
- /*
- * MiniMailer.c
- * Copyright © 1992-93, Apple Computer Inc. All Rights Reserved.
- *
- * MiniMailer is an extremely simple mailer demo that allows you to
- * send a TEXT file to a remote address. That's all it does. This
- * demo is only intended to let you gain initial familiarity with
- * the mailer; that's all it does. It is *not* a "real" application.
- *
- * The only, repeat, only intent of this demo is to show you the
- * simplest-possible interaction with the standard mailer. See
- * CollaboDraw for a more extensive real-world application.
- *
- * Oh, it has one other purpose: because it is so small, it can act as
- * a test-bed for exploring the mailer's send functions.
- *
- * Author: Martin Minow, MACDTS.
- * AppleLink: DEVSUPPORT
- *
- */
- #define EXTERN /* Nothing */
- #include "MiniMailer.h"
-
- const SMPEditCommand gMailerEditCommands[] = {
- (SMPEditCommand) -1, /* Edit menu title */
- kSMPUndoCommand, /* kEditUndo */
- (SMPEditCommand) -1, /* --------- */
- kSMPCutCommand, /* kEditCut */
- kSMPCopyCommand, /* kEditCopy */
- kSMPPasteCommand, /* kEditPaste */
- kSMPClearCommand /* kEditClear */
- };
-
- void
- main()
- {
- InitializeMacintosh();
- SetCursor(*GetCursor(watchCursor));
- gQuitNow = FALSE;
- InitializeAppleEvents();
- if (gQuitNow == FALSE)
- InitializeMailer();
- if (gQuitNow == FALSE)
- BuildMailerWindow();
- while (gQuitNow == FALSE) {
- InitCursor();
- SetPort(gMailerWindow); /* Paranoia */
- (void) WaitNextEvent(
- everyEvent,
- &gEventRecord, /* -> Event Record */
- 6L, /* Sleep time */
- NULL /* No mouse region */
- );
- /*
- * First, pass all events to SMPMailerEvent. It will tell us
- * whether we have to process the event or whether it has
- * already been processed. Note that we even pass NULL events.
- */
- gStatus = SMPMailerEvent(
- &gEventRecord, /* -> Event Record */
- &gWhatHappened, /* Result stored here */
- NULL, /* No FrontWindow callback */
- 0 /* No clientData */
- );
- /*
- * If the user clicks on the same destination address twice,
- * we'll get a kSMPAddressAlreadyInList status which we're
- * happy to ignore.
- */
- if (gStatus == kSMPAddressAlreadyInList)
- gStatus = noErr;
- /*
- * If the user cancels an "Enclosure" or similar, SMPMailerEvent
- * returns userCanceledErr. I'm not certain that this is correct.
- */
- if (1 && gStatus == userCanceledErr)
- gStatus = noErr;
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPMailerEvent error status");
- else {
- if (gMailerWindow != NULL) {
- gStatus = SMPGetMailerState(gMailerWindow, &gMailerState);
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPGetMailerState error");
- else if (gMailerChangeCount != gMailerState.changeCount) {
- Str255 work;
-
- gMailerChangeCount = gMailerState.changeCount;
- NumToString(gMailerChangeCount, work);
- SetWTitle(gMailerWindow, work);
- }
- }
- /*
- * If the mailer says that we should handle the event,
- * well, who are we to argue?
- */
- if ((gWhatHappened & kSMPAppMustHandleEventMask) != 0)
- DoApplicationEvent();
- if ((gWhatHappened & kSMPCreateCopyWindowMask) != 0) {
- gCopyInProgress = TRUE;
- }
- else if ((gWhatHappened & kSMPDisposeCopyWindowMask) != 0) {
- gCopyInProgress = FALSE;
- }
- CheckForDestination();
- AdjustMenus(FALSE);
- }
- }
- /*
- * Quitting.
- */
- if (gMailerWindow != NULL) {
- /*
- * This will fail if the user canceled the initial
- * "password" dialog or the mailer couldn't be built.
- */
- gStatus = SMPDisposeMailer(gMailerWindow, FALSE);
- if (gStatus != noErr
- && gStatus != kSMPNoMailerInWindow)
- ErrorAlert(gStatus, "\pSMPDisposeMailer, unexpected error");
- DisposeWindow(gMailerWindow);
- gMailerWindow = NULL;
- }
- ExitToShell();
- }
-
- /*
- * DoApplicationEvent
- * Process events that must be handled by the "ordinary" application.
- * This function dispatches to some event-specific handlers,
- */
- void
- DoApplicationEvent(void)
- {
- WindowPtr theWindow;
- Boolean isActivate;
-
- switch (gEventRecord.what) {
- case kHighLevelEvent:
- DoHighLevelEvent();
- break;
- case mouseDown:
- DoApplicationMouseEvent();
- break;
- case activateEvt:
- isActivate = (gEventRecord.modifiers & activeFlag);
- theWindow = (WindowPtr) gEventRecord.message;
- DoActivateEvent(theWindow, isActivate);
- break;
- case updateEvt:
- DoUpdateEvent();
- break;
- case keyDown:
- case autoKey:
- DoKeyDownEvent();
- break;
- case osEvt:
- /*
- * Multifinder events.
- */
- switch ((unsigned long) gEventRecord.message >> 24) {
- case mouseMovedMessage:
- break; /* Ignore: just do idle */
- case suspendResumeMessage: /* Context switch */
- isActivate = ((gEventRecord.message & resumeFlag) != 0);
- theWindow = FrontWindow();
- DoActivateEvent(theWindow, isActivate);
- break;
- }
- break;
- default: /* Ignore other events */
- break;
- }
- }
-
- /*
- * DoUpdateEvent
- * Handle an update event in our window.
- */
- void
- DoUpdateEvent(void)
- {
- WindowPtr theWindow;
- GrafPtr savePort;
-
- theWindow = (WindowPtr) gEventRecord.message;
- GetPort(&savePort);
- SetPort(theWindow);
- BeginUpdate(theWindow);
- if (theWindow == gMailerWindow
- && EmptyRgn((*theWindow).visRgn) == FALSE) {
- EraseRect(&theWindow->portRect);
- gStatus = SMPDrawMailer(theWindow);
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPDrawMailer, unexpected error");
- DrawControls(theWindow);
- DrawGrowIcon(theWindow);
- }
- EndUpdate(theWindow);
- SetPort(savePort);
- }
-
- /*
- * DoKeyDown
- * The only interesting keystrokes are for menu shortcuts.
- * Everything else should have been handled by the mailer dialog.
- */
- void
- DoKeyDownEvent(void)
- {
- long menuChoice;
-
- /*
- * Check for <CMD><PERIOD> and quit if so. This is
- * not the right way to do this (it fails for non-US
- * keyboards).
- */
- if ((gEventRecord.message & charCodeMask) == '.'
- && (gEventRecord.modifiers & cmdKey) != 0) {
- FlushEvents(keyDown | autoKey, 0);
- gQuitNow = TRUE;
- }
- else if ((gEventRecord.modifiers & cmdKey) != 0) {
- if (gEventRecord.what == keyDown) {
- /*
- * <CMD><Something>.
- */
- menuChoice = MenuKey(gEventRecord.message & charCodeMask);
- if (HiWord(menuChoice) != 0)
- DoMenuCommand(menuChoice);
- else {
- SysBeep(10); /* Bogus <cmd> */
- }
- }
- }
- else {
- SysBeep(10); /* Bogus keystroke */
- }
- }
-
- /*
- * DoActivateEvent
- * Activate or deactivate the window. The mailer will handle this
- * itself.
- */
- void
- DoActivateEvent(
- WindowPtr theWindow,
- Boolean isActivate
- )
- {
- if (theWindow == gMailerWindow && isActivate) {
- ShowWindow(theWindow);
- SelectWindow(theWindow);
- }
- }
-
- /*
- * DoApplicationMouseEvent
- * The user clicked on something. This is either a menu event or
- * a window drag/grow. Note that our windows don't have content
- * other than the mailer.
- */
- void
- DoApplicationMouseEvent(void)
- {
- WindowPtr theWindow;
- register int whichPart;
- Rect tempRect;
- short mailerWidth;
- short mailerContractedHeight;
- short mailerExpandedHeight;
- long newWindowSize;
-
- whichPart = FindWindow(gEventRecord.where, &theWindow);
- if (whichPart == inMenuBar && theWindow != gMailerWindow)
- theWindow = FrontWindow();
- switch (whichPart) {
- case inDesk: /* Ignore random clicks */
- break;
- case inMenuBar:
- DoMenuCommand(MenuSelect(gEventRecord.where));
- break;
- case inDrag:
- tempRect = qd.screenBits.bounds;
- tempRect.top += ((GetMBarHeight() + 1) * 2);
- InsetRect(&tempRect, 4, 4);
- DragWindow(theWindow, gEventRecord.where, &tempRect);
- break;
- case inGrow:
- /*
- * To grow the window, make sure that there is always
- * space for the mailer. This isn't quite correct: if
- * the mailer is contracted, we should allow the window
- * to be set smaller (and grow it automatically if the
- * user clicks on the expansion button).
- */
- gStatus = SMPGetDimensions(
- &mailerWidth,
- &mailerContractedHeight,
- &mailerExpandedHeight
- );
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPGetDimensions");
- else {
- tempRect = qd.screenBits.bounds;
- tempRect.left = mailerWidth + kScrollBarSize;
- tempRect.top = mailerExpandedHeight + kScrollBarSize;
- newWindowSize = GrowWindow(
- gMailerWindow,
- gEventRecord.where,
- &tempRect
- );
- if (newWindowSize != 0) {
- SizeWindow(
- gMailerWindow,
- LoWord(newWindowSize),
- HiWord(newWindowSize),
- TRUE
- );
- }
- }
- break;
- case inContent:
- if (FrontWindow() != theWindow)
- SelectWindow(theWindow);
- else {
- /*
- * Since we don't have any content, there isn't
- * anything interesting we can do here.
- */
- SetPort(theWindow);
- }
- break;
- case inGoAway:
- if (theWindow == gMailerWindow
- && TrackGoAway(theWindow, gEventRecord.where)) {
- /*
- * Quitting: this should check for a pending
- * message to send and give the user a chance
- * to send it before quitting.
- */
- gQuitNow = TRUE;
- }
- break;
- }
- }
-
- /*
- * DoMenuCommand
- * Handle menu choices.
- */
- void
- DoMenuCommand(
- long menuChoice
- )
- {
- WindowPtr theWindow;
- int menuItem;
- GrafPtr savePort;
- Str255 name;
-
- theWindow = FrontWindow();
- menuItem = LoWord(menuChoice);
- switch (HiWord(menuChoice)) {
- case MENU_Apple:
- GetItem(gAppleMenu, menuItem, name);
- if (menuItem == kAppleAbout)
- ; /* No about box */
- else {
- AdjustMenus(TRUE);
- GetPort(&savePort);
- OpenDeskAcc(name);
- SetPort(savePort);
- AdjustMenus(FALSE);
- }
- break;
- case MENU_File:
- switch (menuItem) {
- case kFileSend:
- if (GetFileToSend())
- SendMailMessage();
- break;
- case kFileTestGetListItemInfo:
- TestGetListItemInfo();
- break;
- case kFileTestAddAttachment:
- TestAddAttachment();
- break;
- case kFileTestNoTarget:
- gStatus = SMPGetMailerState(
- gMailerWindow,
- &gMailerState
- );
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPGetMailerState, huh?");
- gLastTargetComponent = gMailerState.targetComponent;
- gStatus = SMPBecomeTarget(
- gMailerWindow,
- FALSE,
- 0
- );
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPBecomeTarget(FALSE), huh?");
- break;
- case kFileTestBecomeTarget:
- gStatus = SMPBecomeTarget(
- gMailerWindow,
- TRUE,
- gLastTargetComponent
- );
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPBecomeTarget(TRUE), huh?");
- break;
- case kFileQuit:
- gQuitNow = TRUE;
- case kFileForceQuit:
- /*
- * This tests what happens if you quit with an open
- * mailer window.
- */
- ExitToShell();
- break;
- }
- break;
- case MENU_Edit:
- /*
- * Since we don't have any data content, the user's
- * menu choice must be for the mailer or a desk accessory.
- */
- gStatus = SMPMailerEditCommand(
- gMailerWindow,
- gMailerEditCommands[menuItem],
- &gWhatHappened
- );
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPMailerEditCommand, huh?");
- else if ((gWhatHappened & kSMPAppMustHandleEventMask)) {
- /*
- * It's for the application. Check for a desk-accessory.
- */
- if (SystemEdit(menuItem - 1) == FALSE) {
- ErrorAlert(gStatus, "\pMiniMailer has no edit commands");
- }
- }
- break;
- default:
- break;
- }
- HiliteMenu(0);
- AdjustMenus(FALSE);
- InitCursor();
- }
-
- /*
- * AdjustMenus
- * Fiddle with the menu options This doesn't quite work correctly.
- * Perhaps we're not recognizing selections in the mailer area.
- */
- void
- AdjustMenus(
- Boolean isDeskAccessory
- )
- {
- Boolean enableUndo;
- Boolean enableCut;
- Boolean enableCopy;
- Boolean enablePaste;
- Boolean enableClear;
-
- EnableItem(gFileMenu, kFileQuit);
- EnableItem(gFileMenu, kFileForceQuit);
- if (isDeskAccessory) {
- EnableItem(gEditMenu, kEditUndo);
- EnableItem(gEditMenu, kEditCut);
- EnableItem(gEditMenu, kEditCopy);
- EnableItem(gEditMenu, kEditPaste);
- EnableItem(gEditMenu, kEditClear);
- }
- else {
- EnableItem(gFileMenu, kFileTestGetListItemInfo);
- EnableItem(gFileMenu, kFileTestAddAttachment);
- if (gMessageHasDestination && gCopyInProgress == FALSE)
- EnableItem(gFileMenu, kFileSend);
- else {
- DisableItem(gFileMenu, kFileSend);
- }
- enableUndo = FALSE;
- enableCut = FALSE;
- enableCopy = FALSE;
- enablePaste = FALSE;
- enableClear = FALSE;
- gStatus = SMPGetMailerState(
- gMailerWindow,
- &gMailerState
- );
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pSMPGetMailerStatus, unexpected error");
- gMailerState.canCut = FALSE;
- gMailerState.canCopy = FALSE;
- gMailerState.canPaste = FALSE;
- gMailerState.canClear = FALSE;
- gMailerState.canSelectAll = FALSE;
- }
- if (gMailerState.isTarget) {
- enableUndo = gMailerState.undoState == kSMPMailerUndo;
- enableCut = gMailerState.canCut;
- enableCopy = gMailerState.canCopy;
- enablePaste = gMailerState.canPaste;
- enableClear = gMailerState.canClear;
- if (enableUndo)
- SetItem(gEditMenu, kEditUndo, gMailerState.undoWhat);
- CheckItem(gFileMenu, kFileTestNoTarget, FALSE);
- CheckItem(gFileMenu, kFileTestBecomeTarget, TRUE);
- EnableItem(gFileMenu, kFileTestNoTarget);
- DisableItem(gFileMenu, kFileTestBecomeTarget);
- }
- else {
- CheckItem(gFileMenu, kFileTestNoTarget, TRUE);
- CheckItem(gFileMenu, kFileTestBecomeTarget, FALSE);
- DisableItem(gFileMenu, kFileTestNoTarget);
- EnableItem(gFileMenu, kFileTestBecomeTarget);
- }
- FixEditMenu(kEditUndo, enableUndo);
- FixEditMenu(kEditCut, enableCut);
- FixEditMenu(kEditCopy, enableCopy);
- FixEditMenu(kEditPaste, enablePaste);
- FixEditMenu(kEditClear, enableClear);
- }
- }
-
- /*
- * FixEditMenu
- * Fiddle the edit menu.
- */
- void
- FixEditMenu(
- short menuItem,
- Boolean enableIt
- )
- {
- if (enableIt)
- EnableItem(gEditMenu, menuItem);
- else {
- DisableItem(gEditMenu, menuItem);
- }
- }
-
- /*
- *** AppleEvent processing.
- */
- typedef struct AEHandlerInstalls {
- AEEventClass eventClass;
- AEEventID eventID;
- EventHandlerProcPtr handlerProc;
- } AEHandlerInstalls;
- #define AEHandler(proc) \
- pascal OSErr proc(AppleEvent *, AppleEvent *, long)
- AEHandler(AEOpenAppHandler);
- AEHandler(AEOpenDocHandler);
- AEHandler(AEPrintHandler);
- AEHandler(AEQuitHandler);
-
- static AEHandlerInstalls gAEHandlers[] = {
- { kCoreEventClass, kAEOpenApplication, AEOpenAppHandler },
- { kCoreEventClass, kAEOpenDocuments, AEOpenAppHandler },
- { kCoreEventClass, kAEPrintDocuments, AEOpenAppHandler },
- { kCoreEventClass, kAEQuitApplication, AEOpenAppHandler },
- { 0, 0, NULL }
- };
-
- /*
- * Install Apple Event handlers. Set gQuitNow on failure.
- */
- void
- InitializeAppleEvents(void)
- {
- long result;
- AEHandlerInstalls *hp;
-
- gStatus = Gestalt(gestaltAppleEventsAttr, &result);
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pWhat, No AppleEvents?");
- else {
- for (hp = gAEHandlers; hp->handlerProc != NULL; hp++) {
- gStatus = AEInstallEventHandler(
- hp->eventClass,
- hp->eventID,
- hp->handlerProc,
- 0,
- FALSE
- );
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pCan't install AppleEvent");
- break;
- }
- }
- }
- if (gStatus != noErr)
- gQuitNow = TRUE;
- }
-
- void
- DoHighLevelEvent(void)
- {
- (void) AEProcessAppleEvent(&gEventRecord);
- }
-
- /*
- * Apple event handlers. Mostly return errors.
- */
- pascal OSErr
- AEOpenAppHandler(
- AppleEvent *eventMessage,
- AppleEvent *eventReply,
- long refCon
- )
- {
- #pragma unused (eventMessage, eventReply, refCon)
- return (noErr);
- }
-
- pascal OSErr
- AEOpenDocHandler(
- AppleEvent *eventMessage,
- AppleEvent *eventReply,
- long refCon
- )
- {
- #pragma unused (eventMessage, eventReply, refCon)
- return (errAEEventNotHandled);
- }
-
- pascal OSErr
- AEPrintHandler(
- AppleEvent *eventMessage,
- AppleEvent *eventReply,
- long refCon
- )
- {
- #pragma unused (eventMessage, eventReply, refCon)
- return (errAEEventNotHandled);
- }
-
- pascal OSErr
- AEQuitHandler(
- AppleEvent *eventMessage,
- AppleEvent *eventReply,
- long refCon
- )
- {
- #pragma unused (eventMessage, eventReply, refCon)
- gQuitNow = TRUE;
- return (noErr);
- }
-
-
- /*
- * InitializeMacintosh
- * Standard application initialization
- */
- void
- InitializeMacintosh()
- {
- short i;
- EventRecord thisEvent;
- long response;
-
- MaxApplZone();
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(NULL);
- HNoPurge((Handle) GetCursor(watchCursor));
- SetCursor(*GetCursor(watchCursor));
- for (i = 0; i < 3; i++)
- EventAvail(everyEvent, &thisEvent);
- SetMenuBar(GetNewMBar(MBAR_MenuBar));
- gAppleMenu = GetMHandle(MENU_Apple);
- AddResMenu(gAppleMenu, 'DRVR');
- gFileMenu = GetMHandle(MENU_File);
- gEditMenu = GetMHandle(MENU_Edit);
- DrawMenuBar();
- if (Gestalt(gestaltQuickdrawVersion, &response) == noErr
- && response >= gestalt8BitQD)
- gHasColorQuickDraw = TRUE;
- InitCursor();
- }
-
- /*
- * The following functions handle AOCE Standard Mail stuff.
- */
-
-
- /*
- * One-time initialization for the mailer. gQuitNow is set TRUE
- * on failure.
- */
- void
- InitializeMailer(void)
- {
- /*
- * Initialize the mailer and create the mailer window.
- */
- gStatus = SystemSupportsAOCE();
- switch (gStatus) {
- case kOCEToolboxNotOpen:
- ErrorAlert(gStatus, "\pAOCE Mailer is not available");
- break;
- case gestaltUndefSelectorErr:
- ErrorAlert(gStatus, "\pAOCE is not installed on this machine");
- break;
- case noErr:
- break;
- default:
- ErrorAlert(gStatus, "\pGestalt: unexpected error");
- }
- if (gStatus != noErr)
- gQuitNow = TRUE;
- else {
- gStatus = GetUserIdentity(&gUserIdentity);
- if (gStatus != noErr) {
- if (gStatus != userCanceledErr)
- ErrorAlert(gStatus, "\pGetUserIdentity");
- gQuitNow = TRUE;
- }
- }
- if (gQuitNow == FALSE) {
- #if OCE_Beta2
- gStatus = SMPInitMailer(0);
- #else
- gStatus = SMPInitMailer();
- #endif
- if (gStatus != noErr) {
- InitCursor();
- ErrorAlert(gStatus, "\pSMPInitMailer: no mail support");
- gQuitNow = TRUE; /* No point going further */
- }
- }
- }
-
- /*
- * BuildMailerWindow
- * Create a window containing a standard mailer.
- */
- void
- BuildMailerWindow(void)
- {
- Rect boundsRect;
- Point mailerCorner;
- short mailerWidth;
- short mailerContractedHeight;
- short mailerExpandedHeight;
-
- boundsRect = qd.screenBits.bounds;
- boundsRect.top += ((GetMBarHeight() + 1) * 2);
- InsetRect(&boundsRect, 4, 4);
- gStatus = SMPGetDimensions(
- &mailerWidth,
- &mailerContractedHeight,
- &mailerExpandedHeight
- );
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPGetDimensions");
- else {
- boundsRect.right = boundsRect.left + mailerWidth;
- boundsRect.bottom = boundsRect.top + mailerExpandedHeight;
- }
- /*
- * Create the mailer window. Change "1" to "0" to force
- * a black/white window on a color system for testing.
- */
- if (1 && gHasColorQuickDraw) {
- gMailerWindow = NewCWindow(
- NULL, /* No window storage */
- &boundsRect, /* Window shape */
- "\pMiniMailer", /* Window title */
- TRUE, /* Visible */
- documentProc, /* Document, no zoom button */
- (WindowPtr) -1L, /* In front */
- TRUE, /* Has goAway */
- 0 /* refCon (ignored) */
- );
- }
- else {
- gMailerWindow = NewWindow(
- NULL, /* No window storage */
- &boundsRect, /* Window shape */
- "\pMiniMailer", /* Window title */
- TRUE, /* Visible */
- documentProc, /* Document, no zoom button */
- (WindowPtr) -1L, /* In front */
- TRUE, /* Has goAway */
- 0 /* refCon (ignored) */
- );
- }
- if (gMailerWindow == NULL) {
- ErrorAlert(MemError(), "\pNewWindow (fatal)");
- ExitToShell();
- }
- SetPort(gMailerWindow); /* Paranoia */
- SetPt(&mailerCorner, 0, 0); /* Location within window */
- gStatus = SMPNewMailer( /* Create Standard Mailer */
- gMailerWindow, /* In this window */
- mailerCorner, /* Mailer top-left */
- FALSE, /* Cannot contract */
- TRUE, /* Initially expanded */
- gUserIdentity, /* Default identity */
- NULL, /* No prepare callback */
- 0 /* No client data */
- );
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pSMPNewMailer (fatal)");
- ExitToShell();
- gLastTargetComponent = kSMPOther;
- gStatus = SMPBecomeTarget(
- gMailerWindow,
- TRUE,
- gLastTargetComponent
- );
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPBecomeTarget(TRUE) at create, huh?");
- }
- }
-
- /*
- * CheckForDestination
- * This is called whenever the mailer window content changes. It
- * checks to see whether there is a destination, setting the global
- * flag as needed. The "File/Send" menu is enabled if (and only if)
- * at least one destination has been specified.
- */
- void
- CheckForDestination(void)
- {
- unsigned short fieldSize;
-
- gStatus = SMPGetComponentSize(
- gMailerWindow, /* In this window */
- 1, /* First (and only) mailer */
- kSMPTo, /* The destination field */
- &fieldSize /* Result */
- );
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pSMPGetComponentSize");
- fieldSize = 0;
- }
- gMessageHasDestination = (fieldSize != 0);
- }
-
-
- /*
- * TestGetListItemInfo
- * This is a temporary test function to see what happens if you call
- * SMPGetListItemInfo when nothing is selected in the to field.
- * This subroutine makes no sense unless you run it with debug
- * traps set appropriately. This test determined that SMPGetListItemInfo
- * returns a paramErr if the user hasn't set anything in the "to" field.
- * The documentation states that SMPGetComponentSize should be called
- * first. If it returns "zero" size, nothing is in the "to" field.
- */
- unsigned char gScratchBuffer[4096];
-
- void
- TestGetListItemInfo(void)
- {
- unsigned short startItem;
- unsigned short itemCount;
- unsigned short nextItem;
- Boolean moreFlag;
-
- for (startItem = 0, moreFlag = TRUE;
- moreFlag;
- startItem = nextItem) {
- gStatus = SMPGetListItemInfo(
- gMailerWindow, /* In this window */
- 1, /* First (and only) mailer */
- kSMPTo, /* The destination field */
- gScratchBuffer, /* Temp buffer */
- sizeof gScratchBuffer, /* Temp buffer size */
- 0, /* Start item */
- &itemCount, /* Item counter */
- &nextItem, /* Next item to be returned */
- &moreFlag /* Is there more to do? */
- );
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pSMPGetListItemInfo");
- break;
- }
- }
- }
-
- /*
- * Test the AddAttachment function.
- */
- void
- TestAddAttachment(void)
- {
- StandardFileReply reply;
-
- StandardGetFile(NULL, -1, NULL, &reply);
- if (reply.sfGood) {
- gStatus = SMPAddAttachment(
- gMailerWindow,
- &reply.sfFile
- );
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pSMPAddAttachment");
- }
- }
-
- /*
- * SendMailMessage
- * This is a modal procedure that sends the current message.
- */
- void
- SendMailMessage(void)
- {
- Boolean sendWasSuccessful;
- StringPtr nativeFormatNames[1];
- SMPSendFormat currentFormat;
-
- nativeFormatNames[0] = "\pMiniMailer";
- currentFormat.whichFormats = kSMPStandardInterchangeMask;
- currentFormat.whichNativeFormat = 0;
- sendWasSuccessful = FALSE;
- gStatus = SMPSendOptionsDialog(
- gMailerWindow, /* The window */
- gMailDocumentTitle, /* Dialog title */
- nativeFormatNames, /* Default native fmt names */
- 1, /* Native format name count */
- kSMPStandardInterchangeMask, /* Just text, please */
- ¤tFormat, /* Current format */
- NULL, /* No filter porc */
- 0, /* No Client data */
- &gSendFormat, /* Should send (result) */
- &gSendOptions /* (result) */
- );
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pSMPSendOptionsDialog");
- goto exit;
- }
- if (gSendFormat.whichFormats == 0) /* Cancel? */
- goto exit;
- SetCursor(*GetCursor(watchCursor));
- gStatus = SMPBeginSend(
- gMailerWindow,
- kMailAppleMailCreator, /* Creator (Letter app) */
- kMailLtrMsgType, /* File type */
- #if OCE_Beta2
- &gSendOptions, /* Send Options Record */
- #else
- gSendOptions, /* Send Options Handle */
- #endif
- &gMustAddContent /* Set by SMPBeginSend */
- );
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pSMPBeginSend");
- goto endSend;
- }
- if (gMustAddContent) /* Anything to add? */
- sendWasSuccessful = SendThisFile(); /* Send the file */
- endSend:
- gStatus = SMPEndSend(gMailerWindow, sendWasSuccessful);
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pSMPEndSend");
- goto exit;
- }
- exit: CloseDataFile();
- }
-
- /*
- * SendThisFile
- * Read a file and stuff it into the mail message. Return TRUE
- * if the process completed correctly. This is needed by SMPEndSend
- * which will delete everything if SendThisFile failed.
- *
- * A real application would display a progress thermometer.
- */
- Boolean
- SendThisFile(void)
- {
- Boolean sendWasSuccessful;
- Boolean startNewScript;
- Boolean appendFlag;
-
- /*
- * This loop reads data from the file and adds it to
- * the mail message.
- * startNewScript TRUE for the first call, then FALSE for
- * successive calls unless you need to
- * change the script code.
- * appendFlag FALSE for the first call, then TRUE
- * for successive calls unless you need
- * to start a new segment (i.e., change
- * from sending text to sending pictures).
- * Since this demo has only one script and one segment type,
- * the flags are fixed in nature.
- */
- sendWasSuccessful = FALSE;
- startNewScript = TRUE;
- appendFlag = FALSE;
- while (gFileAtEOF == FALSE) {
- ReadDataFromFile();
- gStatus = SMPAddContent(
- gMailerWindow, /* The mailer window */
- kMailTextSegmentType, /* This is text */
- appendFlag, /* Append to current */
- gFileDataBuffer, /* The data itself */
- gFileByteCount, /* Data segment size */
- NULL, /* Unstyled text */
- startNewScript, /* New script */
- smRoman /* Script code */
- #if OCE_Beta2 == FALSE
- , gFileAtEOF /* Last block */
- #endif
- );
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pSMPAddContent");
- goto endSend;
- }
- startNewScript = FALSE; /* Use same script */
- appendFlag = TRUE; /* Continue in segment */
- }
- sendWasSuccessful = TRUE;
- endSend:
- return (sendWasSuccessful);
- }
-
- /*
- * GetFileToSend
- * Use the standard "Open..." dialog to get a text file to send.
- * Return TRUE if there's a file, FALSE if the user Cancels.
- * If successful, gFileRefNum has the file reference number.
- */
- Boolean
- GetFileToSend(void)
- {
- SFReply reply;
- Point where;
- SFTypeList typeList;
- Boolean result;
-
- typeList[0] = 'TEXT';
- SetPt(&where, 20, 80);
- SFGetFile(
- where, /* Window location */
- NULL, /* No prompt */
- NULL, /* No filter */
- 1, /* One file type */
- typeList, /* Vector of file types */
- NULL, /* No dialog hook */
- &reply /* File stuff goes here */
- );
- result = reply.good; /* False if Cancel hit */
- if (result) {
- pstrcpy(gMailDocumentTitle, reply.fName);
- gStatus = FSOpen(
- reply.fName, /* The specified file */
- reply.vRefNum, /* On this volume */
- &gFileRefNum /* Here's the file id */
- );
- if (gStatus != noErr) {
- ErrorAlert(gStatus, "\pFSOpen, couldn't open");
- gFileRefNum = (-1);
- result = FALSE;
- }
- }
- if (result) {
- gFileDataBuffer = NewPtr(kFileReadSize);
- if (gFileDataBuffer != NULL)
- gFileAtEOF = FALSE;
- else {
- ErrorAlert(MemError(), "\pNewPtr(data buffer)");
- CloseDataFile();
- result = FALSE;
- }
- }
- return (result);
- }
-
- /*
- * ReadDataFromFile
- * Read a chunk of data from the file. set gFileAtEOF if we
- * read the end of file. Note that there may be data in the
- * last record read (i.e. even if gFileAtEOF is TRUE).
- * gFileDataBuffer contains the data.
- * gFileByteCount the number of bytes read
- * gFileAtEOF TRUE at end of file or error
- */
- void
- ReadDataFromFile(void)
- {
- gFileByteCount = kFileReadSize;
- gStatus = FSRead(
- gFileRefNum,
- &gFileByteCount,
- gFileDataBuffer
- );
- if (gStatus != noErr) {
- gFileAtEOF = TRUE;
- if (gStatus != eofErr) /* EOF is expected */
- ErrorAlert(gStatus, "\pFSRead");
- }
- }
-
- /*
- * CloseDataFile
- * Close the data file.
- */
- void
- CloseDataFile(void)
- {
- gStatus = FSClose(gFileRefNum);
- if (gStatus != noErr)
- ErrorAlert(gStatus, "\pFSClose");
- gFileRefNum = (-1);
- if (gFileDataBuffer != NULL) {
- DisposePtr(gFileDataBuffer);
- gFileDataBuffer = NULL;
- }
- }
-
- /*
- * Get the user's local identity. On success, the identity is
- * stored in the specified location. The only expected error
- * is userCanceledErr, which probably means "just exit the
- * application." Other errors should be displayed.
- */
- OSErr
- GetUserIdentity(
- AuthIdentity *userIdentity
- )
- {
- long gestaltResponse;
- SDPIdentityKind selectedKind;
- AuthParamBlock authParamBlock;
- OSErr status;
-
- /*
- * Make sure this Macintosh supports AOCE.
- */
- status = Gestalt(gestaltOCEToolboxAttr, &gestaltResponse);
- if (status == noErr
- && (gestaltResponse & gestaltOCETBAvailable) == 0)
- status = kOCEToolboxNotOpen;
- if (status == noErr) {
- /*
- * OCE Setup: get the user's local authentication identity. If it's
- * already set, we can do this silently. If it's not set (the system
- * has just been started), we'll prompt for the user's identity
- * and password.
- *
- * The only expected error is "Cancel" from SDPPromptForIdentity.
- */
- status = AuthGetLocalIdentity(
- &authParamBlock, /* Parameter block */
- FALSE /* Synchronous */
- );
- }
- if (status == noErr) {
- /*
- * The user identity has already been specified.
- */
- *userIdentity = authParamBlock.getLocalIdentityPB.theLocalIdentity;
- }
- else if (status == kOCELocalAuthenticationFail) {
- /*
- * No user identity has been specified. Ask for the user to specify
- * the local identity.
- */
- status = SDPPromptForID(
- userIdentity, /* AuthIdentity *id */
- NULL, /* Default guest prompt */
- NULL, /* Default specific prompt */
- NULL, /* Default local prompt */
- NULL, /* RString *recordType */
- ( /* SDPIdentityKind permittedKinds */
- kSDPLocalIdentityMask /* Local identity */
- | kSDPSpecificIdentityMask /* or specific identity */
- ),
- &selectedKind, /* SDPIdentityKind *selectedKind */
- NULL, /* RecordID *loginFilter */
- 0 /* SDPLoginFilterKind filterKind */
- );
- }
- else {
- /* AuthGetLocalIdentity is very unhappy. */
- }
- return (status);
- }
-
- /*
- * Test for the presence of AOCE.
- * Return noErr Installed and available.
- * Return kOCEToolboxNotOpen Installed, but not available,
- * Return gestaltUndefSelectorErr Not present on this machine
- */
- OSErr
- SystemSupportsAOCE(void)
- {
- long gestaltResponse;
- OSErr status;
-
- status = Gestalt(gestaltOCEToolboxAttr, &gestaltResponse);
- if (status == noErr
- && (gestaltResponse & gestaltOCETBAvailable) == 0)
- status = kOCEToolboxNotOpen;
- return (status);
- }
- /*
- * ErrorAlert
- * Display an error message.
- */
- void
- ErrorAlert(
- OSErr status,
- StringPtr messageText
- )
- {
- Str15 errorValue;
-
- NumToString(status, errorValue);
- ParamText(
- errorValue,
- messageText,
- "\p",
- "\p"
- );
- InitCursor();
- StopAlert(ALRT_Error, NULL);
- }